package com.uraurora.crescent.ai.ktbt

import com.uraurora.crescent.ai.bt.BTStatus
import com.uraurora.crescent.ai.bt.BehaviourTree

/**
 * @author gaoxiaodong
 */
interface INode<E> {
    //<editor-fold desc="属性设置">
    /** 返回这个任务属于的黑板对象
     * @throws IllegalStateException 如果该任务从未运行
     */
    val `object`: E
    /** 守护任务
     * @param guard 守护任务
     */
    var guard: INode<E>?

    /** 返回这个任务的状态  */
    var status: BTStatus

    /**
     * 获取该任务所属的行为树 [BehaviourTree]
     * @return 行为树
     */
    val tree: BehaviourTree<E>?

    /**
     * 设置该任任务的父级任务，并将父任务的行为树置为该任务所属的行为树
     * @param control 父任务
     */
    fun setControl(control: INode<E>?)
    //</editor-fold>

    //<editor-fold desc="子任务相关">
    /**
     * 添加一个子任务到该任务的子任务列表中，并通知行为树
     * @param child 需要添加的子任务
     * @return 这个子任务添加的索引
     * @throws IllegalStateException 如果添加不成功的原因
     */
    fun addChild(child: INode<E>?): Int

    /**
     * 返回该任务的子任务的个数
     * @return 返回该任务的子任务的个数
     */
    val childCount: Int

    /** 返回子任务列表中指定索引位置的任务  */
    fun getChild(i: Int): INode<E>?
    //</editor-fold>
    /**
     * 检查守护任务
     * @param control 父任务
     * @return 如果守护任务校验返回SUCCEEDED或者没有守护进程，返回 `true` ，否则返回 `false` .
     * @throws IllegalStateException 如果守护任务返回除了 [BTStatus.SUCCEEDED] 和
     * [BTStatus.FAILED] 的其他状态则抛出
     */
    fun checkGuard(control: INode<E>?): Boolean

    /** 在该任务第一次开始运行前调用该方法一次  */
    fun start()

    /** 这个方法会被以下方法调用 [.success], [.fail] 或 [.cancel], 意味着该任务的状态已经各自被设置成了
     * 以下几种状态 [BTStatus.SUCCEEDED], [BTStatus.FAILED] 或 [BTStatus.CANCELLED]  */
    fun end()

    //<editor-fold desc="节点运行逻辑相关">
    /**
     * 更新任务逻辑的方法，实际实现的方法由 [.running] ,[.success] 或 [.fail] 的某个实现
     */
    fun run()

    /**
     * 在 [.run] 中调用，通知父任务该任务需要被再次运行，并且状态已经置为 [BTStatus.RUNNING]
     */
    fun running()

    /**
     * 在 [.run] 中调用，通知父任务该任务运行完成并且状态已经置为 [BTStatus.SUCCEEDED]
     */
    fun success()

    /** 在 [.run] 中调用，通知父任务该任务运行完成并且状态已经置为 [BTStatus.FAILED]  */
    fun fail()

    /**
     * 当一个子任务运行成功时会调用该方法
     * @param runningTask 运行返回成功的那个任务
     */
    fun childSuccess(runningTask: INode<E>?)

    /**
     * 当一个子任务运行失败时会调用该方法
     * @param runningTask 运行返回失败的那个任务
     */
    fun childFail(runningTask: INode<E>?)

    /**
     * 当该任务的祖先需要再次运行的时候，这个方法被调用
     * @param runningTask 需要再次运行的祖先节点
     * @param reporter the task that reports, usually one of this task's children
     */
    fun childRunning(runningTask: INode<E>?, reporter: INode<E>?)

    /**
     * 取消该任务和该任务下的所有运行的子任务，这个任务只有在该任务运行状态 [BTStatus.RUNNING] 时才可以被调用
     */
    fun cancel()
    //</editor-fold>
    /** 重置该任务和子任务的状态为  */
    fun resetTask()

    //    ITask<E> cloneTask ();
    //     ITask<E> copyTo (ITask<E> task);
}